﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class State : IEnumerable<Transition>
{
    #region Fields

    private string name;
    private Dictionary<string, Transition> transitions;

    #endregion

    public State(string name)
    {
        this.Name = name;
        this.transitions = new Dictionary<string, Transition>();
    }

    #region Properties

    public string Name
    {
        get
        {
            return this.name;
        }
        set
        {
            this.name = value;
        }
    }

    public Transition this[string name]
    {
        get
        {
            return this.transitions[name];
        }
    }

    public int Count
    {
        get
        {
            return this.transitions.Count;
        }
    }

    #endregion

    #region Methods

    public bool AddTransition(Transition transition)
    {
        string toName = transition.To.Name;
        if (this.transitions.ContainsKey(toName))
        {
            this.transitions[toName].AddValues(transition.Values);
            return true;
        }
        this.transitions.Add(transition.To.Name, transition);
        return true;
    }

    public string ToFullString(string epsilonName)
    {
        StringBuilder output = new StringBuilder();
        output.AppendFormat("{0} => ", this.Name);
        output.AppendLine("{");
        string tabulation = new string(' ', 4);
        Transition transition;
        foreach (var pair in this.transitions)
        {
            transition = pair.Value;
            output.Append(tabulation);
            output.AppendLine(transition.ToFullString());
        }
        output.Append("};");
        output.AppendLine();

        return output.ToString();
    }

    public string ToFullString()
    {
        return ToFullString("Epsilon");
    }

    public override string ToString()
    {
        return name.ToString();
    }

    public bool IsDeterministic(HashSet<string> language)
    {
        if (this.Count != language.Count)
        {
            return false;
        }

        Transition transition;
        HashSet<string> usedTransitionValues = new HashSet<string>();
        foreach (var pair in transitions)
        {
            transition = pair.Value;

            if (transition.ContainsEpsilon())
            {
                return false;
            }
            foreach (string value in transition.ValuesSet)
            {
                if (usedTransitionValues.Contains(value))
                {
                    return false;
                }
                if (!language.Contains(value))
                {
                    return false;
                }
                usedTransitionValues.Add(value);
            }   
        }
        return true;
    }

    public IEnumerator<Transition> GetEnumerator()
    {
        foreach (var pair in this.transitions)
        {
            yield return pair.Value;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}